package com.hunan.chinamobile.manager;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.hunan.chinamobile.constant.SysConstant;
import com.hunan.chinamobile.core.BaseController;
import com.hunan.chinamobile.core.Result;
import com.hunan.chinamobile.core.ResultGenerator;
import com.hunan.chinamobile.dto.*;
import com.hunan.chinamobile.service.DeviceService;
import com.hunan.chinamobile.service.ExceptionService;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellUtil;
import org.apache.poi.ss.util.RegionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/fs")
public class FaultStatisticsController extends BaseController {

    private static Logger logger = LoggerFactory.getLogger(FaultStatisticsController.class);
    @Resource
    private ExceptionService exceptionService;
    @Resource
    private DeviceService deviceService;

    @GetMapping("/count")
    public Result index(HttpServletRequest request, HttpServletResponse response){
        UserDTO userDTO = getUser(request, response);
        if(userDTO == null || StringUtils.isEmpty(userDTO.getCityId()))
            return ResultGenerator.genSuccessResult();
        int yearCount = exceptionService.countByCurrYear(userDTO.getCityId());
        ExceptionCount ec = exceptionService.countByCurrMonth(userDTO.getCityId());
        ExceptionCount uc = exceptionService.countByUntreated(userDTO.getCityId());
        Map<String,Integer> resMap = new HashMap<>();
        resMap.put("yearTotalCount",yearCount);
        resMap.put("monthTotalCount",ec.getTotalCount());
        resMap.put("monthVoltageTotalCount",ec.getVoltageTotalCount());
        resMap.put("monthFiberOpticTotalCcount",ec.getFiberOpticTotalCount());
        resMap.put("voltageUntreatedCount",uc.getVoltageUntreatedCount());
        resMap.put("fiberOpticUntreatedCount",uc.getFiberOpticUntreatedCount());
        return ResultGenerator.genSuccessResult(resMap);
    }

    @GetMapping(value = "/download")
    public void download(HttpServletRequest request, HttpServletResponse response,
                           @RequestParam(required = false) String date,
                            @RequestParam(required = false) String cityId) {
        int queryType = queryType(date);
        Map<String,List<ExceptionDTO>> dataMap = queryData(request, response, date,cityId);
        logger.info("====>   query data : "+ JSON.toJSONString(dataMap));
        Map<String,SeDTO> resMap = null;
        List<StatisticsExceptionDTO> list = null;
        String title = date+" 故障统计";
        String unit = "";
        switch (queryType){
            case 1:
                unit = "月";
                resMap = yearHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null));
                break;
            case 2:
                unit = "号";
                resMap = monthHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null));
                break;
            case 3:
                list = dayHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null));
                break;

        }
        logger.info("====>   download data map : "+ JSON.toJSONString(resMap));
        logger.info("====>   download data list : "+ JSON.toJSONString(list));

        HSSFWorkbook wb = new HSSFWorkbook();
        // 创建单元格样式
        HSSFCellStyle cellStyleTitle = wb.createCellStyle();
        // 指定单元格居中对齐
        cellStyleTitle.setAlignment(HorizontalAlignment.CENTER);
        // 指定单元格垂直居中对齐
        cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 指定当单元格内容显示不下时不换行
        cellStyleTitle.setWrapText(false);
        // ------------------------------------------------------------------
        HSSFCellStyle cellStyle = wb.createCellStyle();
        // 指定单元格居中对齐
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 指定单元格垂直居中对齐
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 指定当单元格内容显示不下时换行
        cellStyle.setWrapText(true);

        HSSFFont cf = wb.createFont();
        cf.setBold(true);
        cf.setFontHeightInPoints((short) 12);
        cf.setFontName("宋体");
        cellStyle.setFont(cf);

        // ------------------------------------------------------------------
        // 设置单元格字体
        HSSFFont font = wb.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 28);
        font.setFontName("宋体");
        font.setFontHeight((short) 100);
        cellStyleTitle.setFont(font);
        String[] hs = new String[]{"基站名称","设备名称","总故障时长","电压故障时长","光纤故障时长","总故障次数","电压故障次数","光纤故障次数"};
        if(resMap != null){
            Calendar currM = Calendar.getInstance();
            currM.set(Calendar.YEAR,Integer.parseInt(date.split("-")[0]));
            currM.set(Calendar.MONTH,Integer.parseInt(date.split("-")[1]) - 1);
            int maxDay = currM.getActualMaximum(Calendar.DAY_OF_MONTH);
            Map<String,StatisticsExceptionDTO> stationMap = new HashMap<>();
            while (maxDay > 0){
                SeDTO seDTO = resMap.getOrDefault(String.valueOf(maxDay),null);
                if(seDTO != null){
                    List<StatisticsExceptionDTO> currDayList = seDTO.getList();
                    currDayList.forEach(x->{
                        if(stationMap.containsKey(x.getName())){
                            StatisticsExceptionDTO stationTotal = stationMap.get(x.getName());
                            stationTotal.setTotalCount(stationTotal.getTotalCount() + x.getTotalCount());
                            stationTotal.setTotalTime(stationTotal.getTotalTime() + x.getTotalTime());
                            stationTotal.setVoltageTime(stationTotal.getVoltageTime() + x.getVoltageTime());
                            stationTotal.setVoltageCount(stationTotal.getVoltageCount() + x.getVoltageCount());
                            stationTotal.setFiberOpticTime(stationTotal.getFiberOpticTime() + x.getFiberOpticTime());
                            stationTotal.setFiberOpticCount(stationTotal.getFiberOpticCount() + x.getFiberOpticCount());
                            List<StatisticsExceptionDTO> childList = stationTotal.getChildList();
                            List<StatisticsExceptionDTO> currChildList = x.getChildList();
                            if(currChildList != null && currChildList.size() > 0){
                                for(StatisticsExceptionDTO c : currChildList){
                                    if(childList == null){
                                        childList = new ArrayList<>();
                                        childList.add(c);
                                    }else{
                                        if(childList.stream().anyMatch(y->y.getName().equals(c.getName()))){
                                            StatisticsExceptionDTO yse = childList.stream()
                                                    .filter(y->y.getName().equals(c.getName()))
                                                    .findFirst()
                                                    .get();
                                            yse.setTotalCount(yse.getTotalCount() + c.getTotalCount());
                                            yse.setTotalTime(yse.getTotalTime() + c.getTotalTime());
                                            yse.setVoltageTime(yse.getVoltageTime() + c.getVoltageTime());
                                            yse.setVoltageCount(yse.getVoltageCount() + c.getVoltageCount());
                                            yse.setFiberOpticTime(yse.getFiberOpticTime() + c.getFiberOpticTime());
                                            yse.setFiberOpticCount(yse.getFiberOpticCount() + c.getFiberOpticCount());
                                        }else{
                                            childList.add(c);
                                        }
                                    }
                                }
                            }
                            stationTotal.setChildList(childList);
                        }else{
                            stationMap.put(x.getName(),x);
                        }
                    });
                }
                maxDay--;
            }

            if(stationMap.values().size() > 0) {
                HSSFSheet sheet = wb.createSheet(date+"故障统计");
                int rowIndex = 0;
                HSSFRow r1 = sheet.createRow(rowIndex);
                r1.setHeightInPoints(30);
                for (int i = 0; i < hs.length; i++) {
                    HSSFCell c1 = r1.createCell(i);
                    c1.setCellValue(new HSSFRichTextString(hs[i]));
                    c1.setCellStyle(cellStyle);
                    int w = 25;
                    if (i == 1) w = 30;
                    sheet.setColumnWidth(i, w * 256);
                }

                List<StatisticsExceptionDTO> currMonth = new ArrayList<>();
                currMonth.addAll(stationMap.values());
                currMonth.sort((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()));
                StatisticsExceptionDTO total = new StatisticsExceptionDTO();
                for (StatisticsExceptionDTO se : currMonth) {
                    total.setTotalCount(total.getTotalCount() + se.getTotalCount());
                    total.setTotalTime(total.getTotalTime() + se.getTotalTime());
                    total.setVoltageTime(total.getVoltageTime() + se.getVoltageTime());
                    total.setVoltageCount(total.getVoltageCount() + se.getVoltageCount());
                    total.setFiberOpticTime(total.getFiberOpticTime() + se.getFiberOpticTime());
                    total.setFiberOpticCount(total.getFiberOpticCount() + se.getFiberOpticCount());

                    rowIndex++;
                    HSSFRow bsRow = sheet.createRow(rowIndex);
                    bsRow.setHeightInPoints(20);
                    setCell(wb, bsRow, 0, se.getName());
                    setCell(wb, bsRow, 2, getStr(se.getTotalTime()));
                    setCell(wb, bsRow, 4, getStr(se.getFiberOpticTime()));
                    setCell(wb, bsRow, 3, getStr(se.getVoltageTime()));
                    setCell(wb, bsRow, 5, se.getTotalCount());
                    setCell(wb, bsRow, 7, se.getFiberOpticCount());
                    setCell(wb, bsRow, 6, se.getVoltageCount());
                    List<StatisticsExceptionDTO> childList = se.getChildList();
                    if (childList != null && childList.size() > 0) {
                        childList.sort((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()));
                        for (StatisticsExceptionDTO d : childList) {
                            rowIndex++;
                            HSSFRow dRow = sheet.createRow(rowIndex);
                            dRow.setHeightInPoints(20);
                            setCell(wb, dRow, 1, d.getName());
                            setCell(wb, dRow, 2, getStr(d.getTotalTime()));
                            setCell(wb, dRow, 4, getStr(d.getFiberOpticTime()));
                            setCell(wb, dRow, 3, getStr(d.getVoltageTime()));
                            setCell(wb, dRow, 5, d.getTotalCount());
                            setCell(wb, dRow, 7, d.getFiberOpticCount());
                            setCell(wb, dRow, 6, d.getVoltageCount());
                        }
                    }
                }
                rowIndex++;
                HSSFRow totalRow = sheet.createRow(rowIndex);
                totalRow.setHeightInPoints(20);
                setCell(wb,totalRow,0,"总计");
                setCell(wb,totalRow,2,getStr(total.getTotalTime()));
                setCell(wb,totalRow,4,getStr(total.getFiberOpticTime()));
                setCell(wb,totalRow,3,getStr(total.getVoltageTime()));
                setCell(wb,totalRow,5,total.getTotalCount());
                setCell(wb,totalRow,7,total.getFiberOpticCount());
                setCell(wb,totalRow,6,total.getVoltageCount());

            }

//            for(Map.Entry<String,SeDTO> entry : resMap.entrySet()) {
//                String key = entry.getKey();
//                SeDTO seDTO = entry.getValue();
//                if (seDTO != null) {
//                    HSSFSheet sheet = wb.createSheet(key + unit);
//                    int rowIndex = 0;
//                    HSSFRow r1 = sheet.createRow(rowIndex);
//                    r1.setHeightInPoints(30);
//                    for (int i = 0; i < hs.length; i++) {
//                        HSSFCell c1 = r1.createCell(i);
//                        c1.setCellValue(new HSSFRichTextString(hs[i]));
//                        c1.setCellStyle(cellStyle);
//                        int w = 25;
//                        if (i == 1) w = 30;
//                        sheet.setColumnWidth(i, w * 256);
//                    }
//
//                    List<StatisticsExceptionDTO> dtoList = seDTO.getList();
//                    if (dtoList != null && dtoList.size() > 0) {
//                        dtoList.sort((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()));
//                        for (StatisticsExceptionDTO dto : dtoList) {
//                            rowIndex++;
//                            HSSFRow bsRow = sheet.createRow(rowIndex);
//                            bsRow.setHeightInPoints(20);
//                            setCell(wb, bsRow, 0, dto.getName());
//                            setCell(wb, bsRow, 2, getStr(dto.getTotalTime()));
//                            setCell(wb, bsRow, 3, getStr(dto.getFiberOpticTime()));
//                            setCell(wb, bsRow, 4, getStr(dto.getVoltageTime()));
//                            setCell(wb, bsRow, 5, dto.getTotalCount());
//                            setCell(wb, bsRow, 6, dto.getFiberOpticCount());
//                            setCell(wb, bsRow, 7, dto.getVoltageCount());
//                            List<StatisticsExceptionDTO> childList = dto.getChildList();
//                            if (childList != null && childList.size() > 0) {
//                                childList.sort((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()));
//                                for (StatisticsExceptionDTO d : childList) {
//                                    rowIndex++;
//                                    HSSFRow dRow = sheet.createRow(rowIndex);
//                                    dRow.setHeightInPoints(20);
//                                    setCell(wb, dRow, 1, d.getName());
//                                    setCell(wb, dRow, 2, getStr(d.getTotalTime()));
//                                    setCell(wb, dRow, 3, getStr(d.getFiberOpticTime()));
//                                    setCell(wb, dRow, 4, getStr(d.getVoltageTime()));
//                                    setCell(wb, dRow, 5, d.getTotalCount());
//                                    setCell(wb, dRow, 6, d.getFiberOpticCount());
//                                    setCell(wb, dRow, 7, d.getVoltageCount());
//                                }
//                            }
//                        }
//                    }
//                    StatisticsExceptionDTO totalSE = seDTO.getTotal();
//                    rowIndex++;
//                    HSSFRow totalRow = sheet.createRow(rowIndex);
//                    totalRow.setHeightInPoints(20);
//                    setCell(wb, totalRow, 0, "总计");
//                    setCell(wb, totalRow, 2, getStr(totalSE.getTotalTime()));
//                    setCell(wb, totalRow, 3, getStr(totalSE.getFiberOpticTime()));
//                    setCell(wb, totalRow, 4, getStr(totalSE.getVoltageTime()));
//                    setCell(wb, totalRow, 5, totalSE.getTotalCount());
//                    setCell(wb, totalRow, 6, totalSE.getFiberOpticCount());
//                    setCell(wb, totalRow, 7, totalSE.getVoltageCount());
//                }
//            }
        }

        if(list != null){
            HSSFSheet sheet = wb.createSheet(title);
            int rowIndex = 0;
            HSSFRow r1 = sheet.createRow(rowIndex);
            r1.setHeightInPoints(30);
            for(int i=0;i<hs.length;i++) {
                HSSFCell c1 = r1.createCell(i);
                c1.setCellValue(new HSSFRichTextString(hs[i]));
                c1.setCellStyle(cellStyle);
                int w = 25;
                if(i == 1) w = 30;
                sheet.setColumnWidth(i,w*256);
            }
            list.sort((a,b)->Long.compare(b.getTotalTime(),a.getTotalTime()));
            StatisticsExceptionDTO ts = new StatisticsExceptionDTO();
            for(StatisticsExceptionDTO dto : list){
                rowIndex++;
                HSSFRow bsRow = sheet.createRow(rowIndex);
                bsRow.setHeightInPoints(20);
                setCell(wb,bsRow,0,dto.getName());
                setCell(wb,bsRow,2,getStr(dto.getTotalTime()));
                setCell(wb,bsRow,4,getStr(dto.getFiberOpticTime()));
                setCell(wb,bsRow,3,getStr(dto.getVoltageTime()));
                setCell(wb,bsRow,5,dto.getTotalCount());
                setCell(wb,bsRow,7,dto.getFiberOpticCount());
                setCell(wb,bsRow,6,dto.getVoltageCount());
                List<StatisticsExceptionDTO> childList = dto.getChildList();
                if(childList != null && childList.size() > 0){
                    childList.sort((a,b)->Long.compare(b.getTotalTime(),a.getTotalTime()));
                    for(StatisticsExceptionDTO d : childList){
                        rowIndex++;
                        HSSFRow dRow = sheet.createRow(rowIndex);
                        dRow.setHeightInPoints(20);
                        setCell(wb,dRow,1,d.getName());
                        setCell(wb,dRow,2,getStr(d.getTotalTime()));
                        setCell(wb,dRow,4,getStr(d.getFiberOpticTime()));
                        setCell(wb,dRow,3,getStr(d.getVoltageTime()));
                        setCell(wb,dRow,5,d.getTotalCount());
                        setCell(wb,dRow,7,d.getFiberOpticCount());
                        setCell(wb,dRow,6,d.getVoltageCount());
                    }
                }
                ts.setTotalTime(ts.getTotalTime()+dto.getTotalTime());
                ts.setTotalCount(ts.getTotalCount()+dto.getTotalCount());
                ts.setFiberOpticTime(ts.getFiberOpticTime()+dto.getFiberOpticTime());
                ts.setFiberOpticCount(ts.getFiberOpticCount()+dto.getFiberOpticCount());
                ts.setVoltageCount(ts.getVoltageCount()+dto.getVoltageCount());
                ts.setVoltageTime(ts.getVoltageTime()+dto.getVoltageTime());
            }
            rowIndex++;
            HSSFRow totalRow = sheet.createRow(rowIndex);
            totalRow.setHeightInPoints(20);
            setCell(wb,totalRow,0,"总计");
            setCell(wb,totalRow,2,getStr(ts.getTotalTime()));
            setCell(wb,totalRow,4,getStr(ts.getFiberOpticTime()));
            setCell(wb,totalRow,3,getStr(ts.getVoltageTime()));
            setCell(wb,totalRow,5,ts.getTotalCount());
            setCell(wb,totalRow,7,ts.getFiberOpticCount());
            setCell(wb,totalRow,6,ts.getVoltageCount());
        }



//        HSSFRow titleRow = sheet.createRow(0);
//        titleRow.setHeightInPoints(50);
//        HSSFCell cell = titleRow.createCell(0);
//        cell.setCellValue(new HSSFRichTextString(title));
//        cell.setCellStyle(cellStyleTitle);
//        sheet.addMergedRegion(new CellRangeAddress(0,0,0,8));

//        FileOutputStream fileOut;
//        try {
//            fileOut = new FileOutputStream("E:/"+title+".xls");
//            wb.write(fileOut);
//            fileOut.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        String fileName = title+".xls";
        System.out.println("fileName:" + fileName);
        try {
            fileName = new String(fileName.getBytes("gb2312"),"iso-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.reset();
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);// 指定下载的文件名
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        try {
            OutputStream output = response.getOutputStream();
            wb.write(output);
            output.flush();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        return ResultGenerator.genSuccessResult();
    }

    private void setCell(HSSFWorkbook wb,HSSFRow bsRow,int colIndex,String value){
        HSSFCell bc1 = bsRow.createCell(colIndex);
        if(value.equals("0秒")) value = "-";
        bc1.setCellValue(new HSSFRichTextString(value));

        HSSFCellStyle cellStyle = wb.createCellStyle();
        // 指定当单元格内容显示不下时换行
        cellStyle.setWrapText(true);
        if(colIndex != 1) {
            // 指定单元格居中对齐
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            // 指定单元格垂直居中对齐
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        }
        bc1.setCellStyle(cellStyle);
    }

    private void setCell(HSSFWorkbook wb,HSSFRow bsRow,int colIndex,int value){
        HSSFCell bc1 = bsRow.createCell(colIndex);
        if(value > 0)
        bc1.setCellValue(value);
        else
            bc1.setCellValue(new HSSFRichTextString("-"));

        HSSFCellStyle cellStyle = wb.createCellStyle();
        // 指定当单元格内容显示不下时换行
        cellStyle.setWrapText(true);
        if(colIndex != 1) {
            // 指定单元格居中对齐
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            // 指定单元格垂直居中对齐
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        }
        bc1.setCellStyle(cellStyle);
    }


    private String getStr(long time){
        String totalTime;
        long t = time/1000;
        if(t < 60){
            totalTime = t+"秒";
        }else if(t < 3600){
            totalTime = t/60+"分钟"+t%60+"秒";
        }else if(t < 3600 * 24){
            totalTime = t/3600+"小时"+(t%3600)/60+"分钟"+(t%3600)%60+"秒";
        }else{
            totalTime = t/(3600*24)+"天"+(t%(3600*24))/3600+"小时"+((t%(3600*24))%3600)/60+"分钟"+(((t%(3600*24))%3600)%60)+"秒";
        }
        return totalTime;
    }

    @GetMapping("/index")
    public Result index(HttpServletRequest request, HttpServletResponse response,
                        @RequestParam(required = false) String date){
        if(StringUtils.isEmpty(date)) return ResultGenerator.genFailResult("date is null");
        if(date.length() != 4 && date.length() != 7 && date.length() != 10)
            return ResultGenerator.genFailResult("incorrect format of date");
        int queryType = queryType(date);
        Map<String,List<ExceptionDTO>> dataMap = queryData(request, response, date,"");
        switch (queryType){
            case 1:
                return ResultGenerator.genSuccessResult(yearHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null)));
            case 2:
                return ResultGenerator.genSuccessResult(monthHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null)));
            case 3:
                return ResultGenerator.genSuccessResult(dayHandle(date, dataMap.getOrDefault("currList",null), dataMap.getOrDefault("otherList",null)));
        }
        return ResultGenerator.genSuccessResult();
    }


//    private Object handleException(int queryType,String date,List<ExceptionDTO> queryList,List<ExceptionDTO> otherList){
//        switch (queryType){
//            case 1:
//                return yearHandle(date, queryList, otherList);
//            case 2:
//                return monthHandle(date, queryList, otherList);
//            case 3:
//                return dayHandle(date,queryList,otherList);
//        }
//        return null;
//    }

    private List<StatisticsExceptionDTO> dayHandle(String date,List<ExceptionDTO> queryList,List<ExceptionDTO> otherList){
        SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd");
        List<StatisticsExceptionDTO> resList = new ArrayList<>();
        Map<String,StatisticsExceptionDTO> deviceMap = new HashMap<>();
        Map<String,String> stationNameMap = new HashMap<>();
        Map<String,Set<String>> stationMap = new HashMap<>();
        Calendar dayStartC = Calendar.getInstance();
        dayStartC.set(Calendar.YEAR,Integer.parseInt(date.split("-")[0]));
        dayStartC.set(Calendar.MONTH,Integer.parseInt(date.split("-")[1]) - 1);
        dayStartC.set(Calendar.DAY_OF_MONTH,Integer.parseInt(date.split("-")[2]));
        dayStartC.set(Calendar.HOUR_OF_DAY,0);
        dayStartC.set(Calendar.MINUTE,0);
        dayStartC.set(Calendar.SECOND,0);
        dayStartC.set(Calendar.MILLISECOND,0);
        Calendar dayEndC = Calendar.getInstance();
        dayEndC.set(Calendar.YEAR,Integer.parseInt(date.split("-")[0]));
        dayEndC.set(Calendar.MONTH,Integer.parseInt(date.split("-")[1]) - 1);
        dayEndC.set(Calendar.DAY_OF_MONTH,Integer.parseInt(date.split("-")[2]));
        dayEndC.set(Calendar.HOUR_OF_DAY,23);
        dayEndC.set(Calendar.MINUTE,59);
        dayEndC.set(Calendar.SECOND,59);
        dayEndC.set(Calendar.MILLISECOND,999);
        if(queryList != null && queryList.size() > 0){
            for(ExceptionDTO dto : queryList){
                String dn = dto.getDeviceId();
                int type = dto.getType();
                boolean state = dto.getState();
                StatisticsExceptionDTO se = new StatisticsExceptionDTO();
                se.setType(2);
                if(deviceMap.containsKey(dn)){
                    se = deviceMap.get(dn);
                }else{
                    se.setName(dto.getDeviceName());
                }
                String hapstr = sdfYMD.format(dto.getHappenAt());
                long faultTime;
                long hapTime = hapstr.equals(date) ? dto.getHappenAt().getTime() : dayStartC.getTimeInMillis();
                if(state){
                    String recoverStr = sdfYMD.format(dto.getRecoverAt());
                    if(recoverStr.equals(date)){
                        // 查询日故障事件|查询日恢复故障：故障时长为恢复时间-故障时间
                        faultTime = dto.getRecoverAt().getTime() - hapTime;
                    }else{
                        // 查询日故障事件|后N天恢复故障：故障时长为23：59：59-故障时间
                        faultTime = dayEndC.getTimeInMillis() - hapTime;
                    }
                }else{
                    if(sdfYMD.format(new Date()).equals(date)){
                        //  今日故障事件|今日时长统计：当前查询时间-故障时间
                        faultTime = System.currentTimeMillis() - hapTime;
                    }else{
                        // 查询日故障事件|未恢复：故障时长为23：59：59-故障时间
                        faultTime = dayEndC.getTimeInMillis() - hapTime;
                    }
                }
                stationNameMap.put(dto.getBsId(),dto.getBsName());
                setStatisticData(deviceMap, stationMap, dto, dn, type, se, faultTime);
            }
        }
        if(otherList != null && otherList.size() > 0){
            for(ExceptionDTO dto : otherList){
                String dn = dto.getDeviceId();
                int type = dto.getType();
                boolean state = dto.getState();
                StatisticsExceptionDTO se = new StatisticsExceptionDTO();
                se.setType(2);
                if(deviceMap.containsKey(dn)){
                    se = deviceMap.get(dn);
                }else{
                    se.setName(dto.getDeviceName());
                }
                long faultTime;
                if(state){   // 已恢复
                    String recoverStr = sdfYMD.format(dto.getRecoverAt());
                    if(recoverStr.equals(date)){ // 查询日恢复
                        // 上N天故障事件|查询日恢复故障：故障时长为恢复时间-00：00：00
                        faultTime = dto.getRecoverAt().getTime() - dayStartC.getTimeInMillis();
                    }else{
                        // 上N天故障事件|后N天恢复故障：故障时长为24小时
                        faultTime = 1000 * 60 * 60 * 24;
                    }
                }else{  // 未恢复
                    if(sdfYMD.format(new Date()).equals(date)){
                        // 上N天故障事件：故障时长为当前查询时间-00：00
                        faultTime = System.currentTimeMillis() - dayStartC.getTimeInMillis();
                    }else{
                        // 上N天故障事件|后N天恢复故障：故障时长为24小时
                        faultTime = 1000 * 60 * 60 * 24;
                    }

                }
                stationNameMap.put(dto.getBsId(),dto.getBsName());
                setStatisticData(deviceMap, stationMap, dto, dn, type, se, faultTime);
            }
        }

        for(Map.Entry<String,Set<String>> entry : stationMap.entrySet()){
            String bsId = entry.getKey();
            Set<String> belongDeviceSet = entry.getValue();
            StatisticsExceptionDTO seDTO = new StatisticsExceptionDTO();
            seDTO.setName(stationNameMap.get(bsId));
            seDTO.setType(1);
            List<StatisticsExceptionDTO> childList = new ArrayList<>();
            belongDeviceSet.forEach(x->{
                StatisticsExceptionDTO deviceSE = deviceMap.get(x);
                deviceSE.setTotalCount(deviceSE.getVoltageCount()+deviceSE.getFiberOpticCount());
                deviceSE.setTotalTime(deviceSE.getVoltageTime()+deviceSE.getFiberOpticTime());
                childList.add(deviceSE);
                seDTO.setTotalCount(seDTO.getTotalCount() + deviceSE.getTotalCount());
                seDTO.setTotalTime(seDTO.getTotalTime() + deviceSE.getTotalTime());
                seDTO.setVoltageCount(seDTO.getVoltageCount() + deviceSE.getVoltageCount());
                seDTO.setVoltageTime(seDTO.getVoltageTime() + deviceSE.getVoltageTime());
                seDTO.setFiberOpticCount(seDTO.getFiberOpticCount() + deviceSE.getFiberOpticCount());
                seDTO.setFiberOpticTime(seDTO.getFiberOpticTime() + deviceSE.getFiberOpticTime());
            });
            seDTO.setChildList(childList);
            resList.add(seDTO);
        }
        if(resList.size() > 0){
            resList.sort((a,b)->Long.compare(b.getTotalTime(),a.getTotalTime()));
        }
        return resList;
    }

    private void setStatisticData(Map<String, StatisticsExceptionDTO> deviceMap, Map<String, Set<String>> stationMap, ExceptionDTO dto, String dn, int type, StatisticsExceptionDTO se, long faultTime) {
        if(faultTime < 0) faultTime = 0;
        if(type == 1){
            se.setVoltageCount(se.getVoltageCount()+1);
            se.setVoltageTime(se.getVoltageTime()+faultTime);
        }else if(type == 2){
            se.setFiberOpticCount(se.getFiberOpticCount()+1);
            se.setFiberOpticTime(se.getFiberOpticTime()+faultTime);
        }
        deviceMap.put(dn,se);

        if(stationMap.containsKey(dto.getBsId())){
            stationMap.get(dto.getBsId()).add(dn);
        }else{
            Set<String> st = new HashSet<>();
            st.add(dn); stationMap.put(dto.getBsId(),st);
        }
    }

    private Map<String,SeDTO> monthHandle(String date, List<ExceptionDTO> queryList, List<ExceptionDTO> otherList){
        Calendar gC = Calendar.getInstance();
        gC.set(Calendar.YEAR,Integer.parseInt(date.split("-")[0]));
        gC.set(Calendar.MONTH,Integer.parseInt(date.split("-")[1]) - 1);
        gC.set(Calendar.DAY_OF_MONTH,1);
        gC.set(Calendar.HOUR_OF_DAY,0);
        gC.set(Calendar.MINUTE,0);
        gC.set(Calendar.SECOND,0);
        int maxDay = gC.getActualMaximum(Calendar.DAY_OF_MONTH);
        SimpleDateFormat sdfYM = new SimpleDateFormat("yyyy-MM");
        if(sdfYM.format(new Date()).equals(sdfYM.format(gC.getTime()))){
            maxDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        }
        Calendar lC = Calendar.getInstance();
        lC.set(Calendar.YEAR,Integer.parseInt(date.split("-")[0]));
        lC.set(Calendar.MONTH,Integer.parseInt(date.split("-")[1]) - 1);
        lC.set(Calendar.DAY_OF_MONTH,maxDay);
        lC.set(Calendar.HOUR_OF_DAY,23);
        lC.set(Calendar.MINUTE,59);
        lC.set(Calendar.SECOND,59);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Map<String,List<ExceptionDTO>> dayExceptionMap = new HashMap<>();
        if(queryList != null && queryList.size() > 0) {
            for (ExceptionDTO e : queryList){
                String happenTimeStr = sdf.format(e.getHappenAt());
                int startDay = 1;
                if(sdfYM.format(e.getHappenAt()).equals(date)) {
                    startDay = Integer.parseInt(happenTimeStr.split("-")[2]);
                }
                if(!e.getState()) {
                    int day = startDay;
                    while (day <= maxDay){
                        String dayStr = date+"-"+(day < 10 ? "0"+day:day);
                        checkMapData(dayExceptionMap, e, dayStr);
                        day++;
                    }
                }else {
                    String recoverTimeStr = sdf.format(e.getRecoverAt());
                    int day = maxDay;
                    if(date.equals(sdfYM.format(e.getRecoverAt()))) {
                        day = Integer.parseInt(recoverTimeStr.split("-")[2]);
                    }
                    while (day <= maxDay && day >= startDay){
                        String dayStr = date+"-"+(day < 10 ? "0"+day:day);
                        checkMapData(dayExceptionMap, e, dayStr);
                        day--;
                    }
                }
            }
        }
        Map<String,List<ExceptionDTO>> dayOtherMap = new HashMap<>();
        if(otherList != null && otherList.size() > 0){
            for(ExceptionDTO dto : otherList){
                int day = maxDay;
                if(dto.getRecoverAt() != null && dto.getState() && lC.getTimeInMillis() >= dto.getRecoverAt().getTime()){
                    day = Integer.parseInt(sdf.format(dto.getRecoverAt()).split("-")[2]);
                }
                while (day > 0){
                    String dayStr = date+"-"+(day < 10 ? "0"+day:day);
                    checkMapData(dayOtherMap, dto, dayStr);
                    day--;
                }
            }
        }
        Map<String,SeDTO> resMap = new HashMap<>();
        for(int i=1;i<=maxDay;i++){
            String dayStr = date+"-"+(i < 10 ? "0"+i:i);
            SeDTO seDTO = null;
            List<StatisticsExceptionDTO> stationList = dayHandle(dayStr,dayExceptionMap.getOrDefault(dayStr,null),
                    dayOtherMap.getOrDefault(dayStr,null));
            if(stationList != null && stationList.size() > 0){
                stationList.sort((a,b)->Long.compare(b.getTotalTime(),a.getTotalTime()));
                seDTO = new SeDTO();
                seDTO.setList(stationList);
                StatisticsExceptionDTO stationTotal = new StatisticsExceptionDTO();
                stationList.forEach(x->{
                    stationTotal.setTotalCount(stationTotal.getTotalCount() + x.getTotalCount());
                    stationTotal.setTotalTime(stationTotal.getTotalTime() + x.getTotalTime());
                    stationTotal.setVoltageTime(stationTotal.getVoltageTime() + x.getVoltageTime());
                    stationTotal.setVoltageCount(stationTotal.getVoltageCount() + x.getVoltageCount());
                    stationTotal.setFiberOpticTime(stationTotal.getFiberOpticTime() + x.getFiberOpticTime());
                    stationTotal.setFiberOpticCount(stationTotal.getFiberOpticCount() + x.getFiberOpticCount());
                });
                seDTO.setTotal(stationTotal);
            }
            resMap.put(String.valueOf(i),seDTO);
        }
        return resMap;
    }

    private void checkMapData(Map<String, List<ExceptionDTO>> dayOtherMap, ExceptionDTO dto, String dayStr) {
        if(dayOtherMap.containsKey(dayStr)){
            dayOtherMap.get(dayStr).add(dto);
        }else{
            List<ExceptionDTO> tes = new ArrayList<>();
            tes.add(dto);
            dayOtherMap.put(dayStr,tes);
        }
    }

    private Map<String,SeDTO> yearHandle(String date,List<ExceptionDTO> queryList,List<ExceptionDTO> otherList){
        Map<String,SeDTO> resMap = new HashMap<>();
        Calendar gC = Calendar.getInstance();
        gC.set(Calendar.YEAR,Integer.parseInt(date));
        gC.set(Calendar.MONTH,0);
        gC.set(Calendar.DAY_OF_MONTH,1);
        gC.set(Calendar.HOUR_OF_DAY,0);
        gC.set(Calendar.MINUTE,0);
        gC.set(Calendar.SECOND,0);
        Calendar lC = Calendar.getInstance();
        lC.set(Calendar.YEAR,Integer.parseInt(date));
        lC.set(Calendar.MONTH,11);
        lC.set(Calendar.DAY_OF_MONTH,31);
        lC.set(Calendar.HOUR_OF_DAY,23);
        lC.set(Calendar.MINUTE,59);
        lC.set(Calendar.SECOND,59);
        Map<String,List<ExceptionDTO>> monthExceptionMap = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        int ms = 12;
        int currYear = Calendar.getInstance().get(Calendar.YEAR);
        if( currYear == Integer.parseInt(date)){
            ms = Calendar.getInstance().get(Calendar.MONTH) + 1;
        }
        if(queryList != null && queryList.size() > 0){
            for(ExceptionDTO dto : queryList){
                String monthStr = sdf.format(dto.getHappenAt());
//                checkMapData(monthExceptionMap,dto,monthStr);
                if(dto.getState()){
                    String monthRecoverStr = sdf.format(dto.getRecoverAt());
                    int rm = Integer.parseInt(monthRecoverStr.split("-")[1]);
                    while (rm >= Integer.parseInt(monthStr.split("-")[1])){
                        String currM = date+"-"+(rm < 10 ? "0"+rm:rm);
                        checkMapData(monthExceptionMap,dto,currM);
                        rm--;
                    }
                }else{
                    int hm = Integer.parseInt(monthStr.split("-")[1]);
                    while (hm <= ms){
                        String currM = date+"-"+(hm < 10 ? "0"+hm:hm);
                        checkMapData(monthExceptionMap,dto,currM);
                        hm++;
                    }
                }

            }
        }
        Map<String,List<ExceptionDTO>> monthOtherMap = new HashMap<>();
        if(otherList != null && otherList.size() > 0){
            for(ExceptionDTO dto : otherList){
                int m = ms;
                if(dto.getRecoverAt() != null && dto.getState() && lC.getTimeInMillis() >= dto.getRecoverAt().getTime()){
                    m = Integer.parseInt(sdf.format(dto.getRecoverAt()).split("-")[1]);
                }
                while (m > 0){
                    String monthStr = date+"-"+(m < 10 ? "0"+m:m);
                    checkMapData(monthOtherMap, dto, monthStr);
                    m--;
                }
            }
        }

        for(int i=1;i<=ms;i++){
            String monthStr = date+"-"+(i < 10 ? "0"+i:i);
            Map<String,SeDTO> monthMap = monthHandle(monthStr,monthExceptionMap.getOrDefault(monthStr,null),monthOtherMap.getOrDefault(monthStr,null));
            Map<String,StatisticsExceptionDTO> stationMap = new HashMap<>();
            if(monthMap != null && monthMap.size() > 0){
                Calendar currM = Calendar.getInstance();
                currM.set(Calendar.YEAR,Integer.parseInt(date));
                currM.set(Calendar.MONTH,i - 1);
                int maxDay = currM.getActualMaximum(Calendar.DAY_OF_MONTH);
                while (maxDay > 0){
                    SeDTO seDTO = monthMap.getOrDefault(String.valueOf(maxDay),null);
                    if(seDTO != null){
                        List<StatisticsExceptionDTO> currDayList = seDTO.getList();
                        currDayList.forEach(x->{
                            if(stationMap.containsKey(x.getName())){
                                StatisticsExceptionDTO stationTotal = stationMap.get(x.getName());
                                stationTotal.setTotalCount(stationTotal.getTotalCount() + x.getTotalCount());
                                stationTotal.setTotalTime(stationTotal.getTotalTime() + x.getTotalTime());
                                stationTotal.setVoltageTime(stationTotal.getVoltageTime() + x.getVoltageTime());
                                stationTotal.setVoltageCount(stationTotal.getVoltageCount() + x.getVoltageCount());
                                stationTotal.setFiberOpticTime(stationTotal.getFiberOpticTime() + x.getFiberOpticTime());
                                stationTotal.setFiberOpticCount(stationTotal.getFiberOpticCount() + x.getFiberOpticCount());
                                List<StatisticsExceptionDTO> childList = stationTotal.getChildList();
                                List<StatisticsExceptionDTO> currChildList = x.getChildList();
                                if(currChildList != null && currChildList.size() > 0){
                                    for(StatisticsExceptionDTO c : currChildList){
                                        if(childList == null){
                                            childList = new ArrayList<>();
                                            childList.add(c);
                                        }else{
                                            if(childList.stream().anyMatch(y->y.getName().equals(c.getName()))){
                                                StatisticsExceptionDTO yse = childList.stream()
                                                        .filter(y->y.getName().equals(c.getName()))
                                                        .findFirst()
                                                        .get();
                                                yse.setTotalCount(yse.getTotalCount() + c.getTotalCount());
                                                yse.setTotalTime(yse.getTotalTime() + c.getTotalTime());
                                                yse.setVoltageTime(yse.getVoltageTime() + c.getVoltageTime());
                                                yse.setVoltageCount(yse.getVoltageCount() + c.getVoltageCount());
                                                yse.setFiberOpticTime(yse.getFiberOpticTime() + c.getFiberOpticTime());
                                                yse.setFiberOpticCount(yse.getFiberOpticCount() + c.getFiberOpticCount());
                                            }else{
                                                childList.add(c);
                                            }
                                        }
                                    }
                                }
                                stationTotal.setChildList(childList);
                            }else{
                                stationMap.put(x.getName(),x);
                            }
                        });
                    }
                    maxDay--;
                }
            }

            SeDTO seDTO = null;
            if(stationMap.values().size() > 0) {
                seDTO = new SeDTO();
                List<StatisticsExceptionDTO> list = new ArrayList<>();
                StatisticsExceptionDTO total = new StatisticsExceptionDTO();
                for (StatisticsExceptionDTO se : stationMap.values()) {
                    list.add(se);
                    total.setTotalCount(total.getTotalCount() + se.getTotalCount());
                    total.setTotalTime(total.getTotalTime() + se.getTotalTime());
                    total.setVoltageTime(total.getVoltageTime() + se.getVoltageTime());
                    total.setVoltageCount(total.getVoltageCount() + se.getVoltageCount());
                    total.setFiberOpticTime(total.getFiberOpticTime() + se.getFiberOpticTime());
                    total.setFiberOpticCount(total.getFiberOpticCount() + se.getFiberOpticCount());
                }
                list.sort((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()));
                seDTO.setList(list);
                seDTO.setTotal(total);
            }
            resMap.put(String.valueOf(i),seDTO);
        }
        return resMap;
    }

    private int queryType(String date){
        String[] dd = date.split("-");
        int queryType = 0;
        if(dd.length == 1){
            queryType = 1;
        }else if(dd.length == 2){
            queryType = 2;
        }else if(dd.length == 3){
            queryType = 3;
        }
        return queryType;
    }

    private Map<String,List<ExceptionDTO>> queryData(HttpServletRequest request, HttpServletResponse response,String date,String cid){
        UserDTO userDTO = getUser(request, response);
        String cityId = cid;
        if(userDTO != null && userDTO.getRoleName().equals(SysConstant.ROLE_USER)){
            cityId = userDTO.getCityId();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String[] dd = date.split("-");
        String startTimeStr;
        String endTimeStr;
        Calendar gC = Calendar.getInstance();
        Calendar lC = Calendar.getInstance();
        if(dd.length == 1){
            gC.set(Calendar.YEAR,Integer.parseInt(date));
            gC.set(Calendar.MONTH,0);
            gC.set(Calendar.DAY_OF_MONTH,1);
            gC.set(Calendar.HOUR_OF_DAY,0);
            gC.set(Calendar.MINUTE,0);
            gC.set(Calendar.SECOND,0);
            lC.set(Calendar.YEAR,Integer.parseInt(date));
            lC.set(Calendar.MONTH,11);
            lC.set(Calendar.DAY_OF_MONTH,31);
            lC.set(Calendar.HOUR_OF_DAY,23);
            lC.set(Calendar.MINUTE,59);
            lC.set(Calendar.SECOND,59);
        }else if(dd.length == 2){
            gC.set(Calendar.YEAR,Integer.parseInt(dd[0]));
            gC.set(Calendar.MONTH,Integer.parseInt(dd[1]) - 1);
            gC.set(Calendar.DAY_OF_MONTH,1);
            gC.set(Calendar.HOUR_OF_DAY,0);
            gC.set(Calendar.MINUTE,0);
            gC.set(Calendar.SECOND,0);
            int maxDay = gC.getActualMaximum(Calendar.DAY_OF_MONTH);
            lC.set(Calendar.YEAR,Integer.parseInt(dd[0]));
            lC.set(Calendar.MONTH,Integer.parseInt(dd[1]) - 1);
            lC.set(Calendar.DAY_OF_MONTH,maxDay);
            lC.set(Calendar.HOUR_OF_DAY,23);
            lC.set(Calendar.MINUTE,59);
            lC.set(Calendar.SECOND,59);
        }else if(dd.length == 3){
            gC.set(Calendar.YEAR,Integer.parseInt(dd[0]));
            gC.set(Calendar.MONTH,Integer.parseInt(dd[1]) - 1);
            gC.set(Calendar.DAY_OF_MONTH,Integer.parseInt(dd[2]));
            gC.set(Calendar.HOUR_OF_DAY,0);
            gC.set(Calendar.MINUTE,0);
            gC.set(Calendar.SECOND,0);
            lC.set(Calendar.YEAR,Integer.parseInt(dd[0]));
            lC.set(Calendar.MONTH,Integer.parseInt(dd[1]) - 1);
            lC.set(Calendar.DAY_OF_MONTH,Integer.parseInt(dd[2]));
            lC.set(Calendar.HOUR_OF_DAY,23);
            lC.set(Calendar.MINUTE,59);
            lC.set(Calendar.SECOND,59);
        }
        startTimeStr = sdf.format(gC.getTime());
        endTimeStr = sdf.format(lC.getTime());


        // 查询期内故障事件
        List<ExceptionDTO> queryList = exceptionService.findByQuery(startTimeStr,endTimeStr);
        String dns = "";
        List<String> ids = new ArrayList<>();
        if(!StringUtils.isEmpty(cityId)){
            List<DeviceDTO> deviceDTOS = deviceService.findList(cityId,null,null,null,null);
            StringBuilder sb = new StringBuilder("(");
            if(deviceDTOS != null && deviceDTOS.size() > 0){
                deviceDTOS.forEach(x->{
                    ids.add(x.getDeviceId());
                    sb.append("'").append(x.getDeviceId()).append("',");
                });
                sb.deleteCharAt(sb.length() - 1).append(")");
//                if (sb.length() > 4) dns = sb.toString();
            }
            if(queryList != null && queryList.size() > 0){
                if(ids.size() <= 0) queryList = null;
                else queryList = queryList.stream().filter(x->ids.contains(x.getDeviceId())).collect(Collectors.toList());
            }
        }
        // 查询期前故障事件
        List<ExceptionDTO> otherList = exceptionService.findByNotQuery(dns, startTimeStr);
        if(otherList != null && otherList.size() > 0 && !StringUtils.isEmpty(cityId)){
            if(ids.size() > 0){
                otherList = otherList.stream().filter(x->ids.contains(x.getDeviceId())).collect(Collectors.toList());
            }else{
                otherList = null;
            }
        }
        Map<String,List<ExceptionDTO>> resMap = new HashMap<>();
        resMap.put("currList",queryList);
        resMap.put("otherList",otherList);
        return resMap;
    }
}
